# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.884.1.9+1.884.2.2 -> 1.884.8.1 # include/asm-i386/fixmap.h 1.4.2.1 -> 1.4.1.2 # Makefile 1.190.1.10 -> 1.193.1.8 # drivers/char/agp/agpgart_be.c 1.35.1.6 -> 1.41.1.9 # drivers/char/Config.in 1.39.1.2 -> 1.39.1.3 # drivers/pci/pci.c 1.36.1.7 -> 1.38.1.3 # arch/i386/config.in 1.34.2.3 -> 1.34.1.4 # drivers/char/Makefile 1.26.1.1 -> 1.28 # include/linux/pci_ids.h 1.44.1.6 -> 1.46.1.3 # drivers/char/agp/agp.h 1.18.1.1 -> 1.22 # drivers/input/joydev.c 1.6.1.1 -> 1.8 # Documentation/Configure.help 1.128.12.18 -> 1.128.13.3 # diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help Wed Oct 8 09:08:18 2003 +++ b/Documentation/Configure.help Wed Oct 8 09:08:18 2003 @@ -18477,70 +18477,64 @@ will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. -ACPI support -CONFIG_ACPI - ACPI/OSPM support for Linux is currently under development. As such, - this support is preliminary and EXPERIMENTAL. Configuring ACPI - support enables kernel interfaces that allow higher level software - (OSPM) to manipulate ACPI defined hardware and software interfaces, - including the evaluation of ACPI control methods. If unsure, choose - N here. Note, this option will enlarge your kernel by about 120K. - - This support requires an ACPI compliant platform (hardware/firmware). - If both ACPI and Advanced Power Management (APM) support are - configured, whichever is loaded first shall be used. - - This code DOES NOT currently provide a complete OSPM implementation - -- it has not yet reached APM's level of functionality. When fully - implemented, Linux ACPI/OSPM will provide a more robust functional - replacement for legacy configuration and power management - interfaces, including the Plug-and-Play BIOS specification (PnP - BIOS), the Multi-Processor Specification (MPS), and the Advanced - Power Management specification (APM). - - Linux support for ACPI/OSPM is based on Intel Corporation's ACPI - Component Architecture (ACPI CA). The latest ACPI CA source code, - documentation, debug builds, and implementation status information - can be downloaded from: - . - - The ACPI Sourceforge project may also be of interest: - - -Enable ACPI 2.0 with errata 1.3 -CONFIG_ACPI20 - Enable support for the 2.0 version of the ACPI interpreter. See the - help for ACPI for caveats and discussion. - -ACPI kernel configuration manager -CONFIG_ACPI_KERNEL_CONFIG - If you say `Y' here, Linux's ACPI support will use the - hardware-level system descriptions found on IA64 machines. - -ACPI Debug Statements -CONFIG_ACPI_DEBUG - The ACPI driver can optionally report errors with a great deal - of verbosity. Saying Y enables these statements. This will increase - your kernel size by around 50K. +ACPI Support +CONFIG_ACPI_ENABLE + Advanced Configuration and Power Interface (ACPI) support for + Linux requires an ACPI compliant platform (hardware/firmware), + and assumes the presence of OS-directed configuration and power + management (OSPM) software. This option will enlarge your + kernel by about 70K. + + Linux ACPI provides a robust functional replacement for several + legacy configuration and power management intefaces, including + the Plug-and-Play BIOS specification (PnP BIOS), the + MultiProcessor Specification (MPS), and the Advanced Power + Management (APM) specification. If both ACPI and APM support + are configured, whichever is loaded first shall be used. + + Add "acpi=off" to the kernel command line to disable this feature. + (Try "man bootparam" or see the documentation of your boot loader + about how to pass options to the kernel at boot time.) + + Add "acpi=ht-only" to the kernel command line to limit ACPI + support to processor enumeration only (see CONFIG_ACPI_HT_ONLY). + + ---------- + + The ACPI SourceForge project contains the latest source code, + documentation, tools, mailing list subscription, and other + information. This project is available at: + + + Linux support for ACPI is based on Intel Corporation's ACPI + Component Architecture (ACPI CA). For more information see: + + + ACPI is an open industry specification co-developed by Compaq, + Intel, Microsoft, Phoenix, and Toshiba. The specification is + available at: + + +CONFIG_ACPI_HT_ONLY + This option enables limited ACPI support -- just enough to + enumerate processors from the ACPI Multiple APIC Description + Table (MADT). Note that ACPI supports both logical (e.g. Hyper- + Threading) and physical processors, where the MultiProcessor + Specification (MPS) table only supports physical processors. -ACPI Bus Manager -CONFIG_ACPI_BUSMGR - The ACPI Bus Manager enumerates devices in the ACPI namespace, and - handles PnP messages. All ACPI devices use its services, so using - them requires saying Y here. + Full ACPI support (CONFIG_ACPI) is preferred. Use this option + only if you wish to limit ACPI's role to processor enumeration. -ACPI System Driver -CONFIG_ACPI_SYS - This driver will enable your system to shut down using ACPI, and - dump your ACPI DSDT table using /proc/acpi/dsdt. +CONFIG_ACPI_AC + This driver adds support for the AC Adapter object, which indicates + whether a system is on AC, or not. Typically, only mobile systems + have this object, since desktops are always on AC. -ACPI Processor Driver -CONFIG_ACPI_CPU - This driver installs ACPI as the idle handler for Linux, and uses - ACPI C2 and C3 processor states to save power, on systems that - support it. +CONFIG_ACPI_BATTERY + This driver adds support for battery information through + /proc/acpi/battery. If you have a mobile system with a battery, + say Y. -ACPI Button CONFIG_ACPI_BUTTON This driver registers for events based on buttons, such as the power, sleep, and lid switch. In the future, a daemon will read @@ -18548,27 +18542,34 @@ down the system. Until then, you can cat it, and see output when a button is pressed. -ACPI AC Adapter -CONFIG_ACPI_AC - This driver adds support for the AC Adapter object, which indicates - whether a system is on AC, or not. Typically, only laptops have - this object, since desktops are always on AC. - -ACPI Embedded Controller CONFIG_ACPI_EC This driver is required on some systems for the proper operation of - the battery and thermal drivers. If you are compiling for a laptop, - say Y. + the battery and thermal drivers. If you are compiling for a + mobile system, say Y. -ACPI Control Method Battery -CONFIG_ACPI_CMBATT - This driver adds support for battery information through - /proc/acpi/battery. If you have a laptop with a battery, say Y. +CONFIG_ACPI_PROCESSOR + This driver installs ACPI as the idle handler for Linux, and uses + ACPI C2 and C3 processor states to save power, on systems that + support it. -ACPI Thermal CONFIG_ACPI_THERMAL - This driver handles overheating conditions on laptops. It is HIGHLY - recommended, as your laptop CPU may be damaged without it. + This driver adds support for ACPI thermal zones. Most mobile and + some desktop systems support ACPI thermal zones. It is HIGHLY + recommended that this option be enabled, as your processor(s) + may be damaged without it. + +CONFIG_ACPI_FAN + This driver adds support for ACPI fan devices, allowing user-mode + applications to perform basic fan control (on, off, status). + +CONFIG_ACPI_SYSTEM + This driver will enable your system to shut down using ACPI, and + dump your ACPI DSDT table using /proc/acpi/dsdt. + +CONFIG_ACPI_DEBUG + The ACPI driver can optionally report errors with a great deal + of verbosity. Saying Y enables these statements. This will increase + your kernel size by around 50K. Advanced Power Management BIOS support CONFIG_APM @@ -25668,12 +25669,31 @@ and restore instructions. It's useful for tracking down spinlock problems, but slow! If you're unsure, select N. -Early printk support (requires VGA!) +Early printk support CONFIG_IA64_EARLY_PRINTK - Selecting this option uses the VGA screen for printk() output before - the consoles are initialised. It is useful for debugging problems - early in the boot process, but only if you have a VGA screen - attached. If you're unsure, select N. + Selecting this option uses a UART or VGA screen (or both) for + printk() output before the consoles are initialised. It is useful + for debugging problems early in the boot process, but only if you + have a serial terminal or a VGA screen attached. If you're unsure, + select N. + +Early printk on serial port +CONFIG_IA64_EARLY_PRINTK_UART + Select this option to use a serial port for early printk() output. + You must also select either CONFIG_IA64_EARLY_PRINTK_UART_BASE or + CONFIG_SERIAL_HCDP. If you select CONFIG_SERIAL_HCDP, early + printk() output will appear on the first console device described by + the HCDP. If you set CONFIG_IA64_EARLY_PRINTK_UART_BASE, the HCDP + will be ignored. + +UART base address +CONFIG_IA64_EARLY_PRINTK_UART_BASE + The physical MMIO address of the UART to use for early printk(). + This overrides any UART located using the EFI HCDP table. + +Early printk on VGA +CONFIG_IA64_EARLY_PRINTK_VGA + Select this option to use VGA for early printk() output. Print possible IA64 hazards to console CONFIG_IA64_PRINT_HAZARDS diff -Nru a/Makefile b/Makefile --- a/Makefile Wed Oct 8 09:08:18 2003 +++ b/Makefile Wed Oct 8 09:08:18 2003 @@ -90,6 +90,7 @@ CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ -fno-strict-aliasing -fno-common +CFLAGS += -g ifndef CONFIG_FRAME_POINTER CFLAGS += -fomit-frame-pointer endif @@ -300,8 +301,7 @@ $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in xconfig: symlinks - $(MAKE) -C scripts kconfig.tk - wish -f scripts/kconfig.tk + @echo -e "***\n* Sorry, xconfig is broken; use \"make menuconfig\" instead.\n***" menuconfig: include/linux/version.h symlinks $(MAKE) -C scripts/lxdialog all diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Wed Oct 8 09:08:18 2003 +++ b/arch/i386/config.in Wed Oct 8 09:08:18 2003 @@ -311,14 +311,6 @@ bool 'Power Management support' CONFIG_PM -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM - - if [ "$CONFIG_ACPI" != "n" ]; then - source drivers/acpi/Config.in - fi -fi - dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM if [ "$CONFIG_APM" != "n" ]; then bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND @@ -329,6 +321,8 @@ bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi + +source drivers/acpi/Config.in endmenu diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in --- a/drivers/char/Config.in Wed Oct 8 09:08:18 2003 +++ b/drivers/char/Config.in Wed Oct 8 09:08:18 2003 @@ -155,6 +155,7 @@ bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT + dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT fi if [ "$CONFIG_PPC64" ] ; then diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Wed Oct 8 09:08:18 2003 +++ b/drivers/char/Makefile Wed Oct 8 09:08:18 2003 @@ -205,6 +205,7 @@ obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o +obj-$(CONFIG_TIPAR) += tipar.o ifeq ($(CONFIG_INPUT),y) obj-y += joystick/js.o diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h --- a/drivers/char/agp/agp.h Wed Oct 8 09:08:18 2003 +++ b/drivers/char/agp/agp.h Wed Oct 8 09:08:18 2003 @@ -229,6 +229,9 @@ #ifndef PCI_DEVICE_ID_INTEL_82443GX_1 #define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #endif +#ifndef PCI_DEVICE_ID_INTEL_460GX +#define PCI_DEVICE_ID_INTEL_460GX 0x84ea +#endif #ifndef PCI_DEVICE_ID_AMD_IRONGATE_0 #define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006 #endif @@ -280,6 +283,15 @@ #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 +/* Intel 460GX Registers */ +#define INTEL_I460_APBASE 0x10 +#define INTEL_I460_BAPBASE 0x98 +#define INTEL_I460_GXBCTL 0xa0 +#define INTEL_I460_AGPSIZ 0xa2 +#define INTEL_I460_ATTBASE 0xfe200000 +#define INTEL_I460_GATT_VALID (1UL << 24) +#define INTEL_I460_GATT_COHERENT (1UL << 25) + /* intel i830 registers */ #define I830_GMCH_CTRL 0x52 #define I830_GMCH_ENABLED 0x4 @@ -412,13 +424,15 @@ #define SVWRKS_POSTFLUSH 0x14 #define SVWRKS_DIRFLUSH 0x0c -/* HP ZX1 SBA registers */ -#define HP_ZX1_CTRL 0x200 +/* HP ZX1 IOC registers */ #define HP_ZX1_IBASE 0x300 #define HP_ZX1_IMASK 0x308 #define HP_ZX1_PCOM 0x310 #define HP_ZX1_TCNFG 0x318 #define HP_ZX1_PDIR_BASE 0x320 -#define HP_ZX1_CACHE_FLUSH 0x428 + +/* HP ZX1 LBA registers */ +#define HP_ZX1_AGP_STATUS 0x64 +#define HP_ZX1_AGP_COMMAND 0x68 #endif /* _AGP_BACKEND_PRIV_H */ diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c --- a/drivers/char/agp/agpgart_be.c Wed Oct 8 09:08:18 2003 +++ b/drivers/char/agp/agpgart_be.c Wed Oct 8 09:08:18 2003 @@ -39,10 +39,14 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include #include #include "agp.h" @@ -207,10 +211,14 @@ agp_bridge.free_by_type(curr); return; } - if (curr->page_count != 0) { - for (i = 0; i < curr->page_count; i++) { - agp_bridge.agp_destroy_page((unsigned long) - phys_to_virt(curr->memory[i])); + if (agp_bridge.cant_use_aperture) { + vfree(curr->vmptr); + } else { + if (curr->page_count != 0) { + for (i = 0; i < curr->page_count; i++) { + agp_bridge.agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[i])); + } } } agp_free_key(curr->key); @@ -219,6 +227,37 @@ MOD_DEC_USE_COUNT; } +#define IN_VMALLOC(_x) (((_x) >= VMALLOC_START) && ((_x) < VMALLOC_END)) + +/* + * Look up and return the pte corresponding to addr. We only do this for + * agp_ioremap'ed addresses. + */ +static pte_t *agp_lookup_pte(unsigned long addr) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + + if (!IN_VMALLOC(addr)) + return NULL; + + dir = pgd_offset_k(addr); + pmd = pmd_offset(dir, addr); + + if (pmd) { + pte = pte_offset(pmd, addr); + + if (pte) { + return pte; + } else { + return NULL; + } + } else { + return NULL; + } +} + #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) agp_memory *agp_allocate_memory(size_t page_count, u32 type) @@ -253,18 +292,43 @@ MOD_DEC_USE_COUNT; return NULL; } - for (i = 0; i < page_count; i++) { - new->memory[i] = agp_bridge.agp_alloc_page(); - if (new->memory[i] == 0) { - /* Free this structure */ - agp_free_memory(new); + if (agp_bridge.cant_use_aperture) { + void *vmblock; + unsigned long vaddr; + pte_t *pte; + + vmblock = __vmalloc(page_count << PAGE_SHIFT, GFP_KERNEL, PAGE_KERNEL); + if (vmblock == NULL) { + MOD_DEC_USE_COUNT; return NULL; } - new->memory[i] = virt_to_phys((void *) new->memory[i]); - new->page_count++; - } + new->vmptr = vmblock; + vaddr = (unsigned long) vmblock; + + for (i = 0; i < page_count; i++, vaddr += PAGE_SIZE) { + pte = agp_lookup_pte(vaddr); + if (pte == NULL) { + MOD_DEC_USE_COUNT; + return NULL; + } + new->memory[i] = virt_to_phys(page_address(pte_page(*pte))); + } + new->page_count = page_count; + } else { + for (i = 0; i < page_count; i++) { + new->memory[i] = agp_bridge.agp_alloc_page(); + + if (new->memory[i] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[i] = virt_to_phys((void *) new->memory[i]); + new->page_count++; + } + } return new; } @@ -305,6 +369,9 @@ /* Routine to copy over information structure */ +/* AGP bridge need not be PCI device, but DRM thinks it is. */ +static struct pci_dev fake_bridge_dev; + int agp_copy_info(agp_kern_info * info) { memset(info, 0, sizeof(agp_kern_info)); @@ -314,7 +381,7 @@ } info->version.major = agp_bridge.version->major; info->version.minor = agp_bridge.version->minor; - info->device = agp_bridge.dev; + info->device = agp_bridge.dev ? agp_bridge.dev : &fake_bridge_dev; info->chipset = agp_bridge.type; info->mode = agp_bridge.mode; info->aper_base = agp_bridge.gart_bus_addr; @@ -388,97 +455,104 @@ /* Generic Agp routines - Start */ -static void agp_generic_agp_enable(u32 mode) +static u32 agp_collect_device_status(u32 mode, u32 command) { - struct pci_dev *device = NULL; - u32 command, scratch; - u8 cap_ptr; - - pci_read_config_dword(agp_bridge.dev, - agp_bridge.capndx + 4, - &command); - - /* - * PASS1: go throu all devices that claim to be - * AGP devices and collect their data. - */ - + struct pci_dev *device; + u8 agp; + u32 scratch; pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ + agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; + + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + pci_read_config_dword(device, agp + PCI_AGP_STATUS, &scratch); - pci_read_config_dword(device, cap_ptr + 4, &scratch); + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min_t(u32, (mode & 0xff000000), + min_t(u32, (command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW if it's not supported */ + if (!((command & 0x00000010) && + (scratch & 0x00000010) && + (mode & 0x00000010))) + command &= ~0x00000010; - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; - - /* disable FW if it's not supported */ - if (!((command & 0x00000010) && - (scratch & 0x00000010) && - (mode & 0x00000010))) - command &= ~0x00000010; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; - } + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; } - /* - * PASS2: Figure out the 4X/2X/1X setting and enable the - * target (our motherboard chipset). - */ - if (command & 4) { + if (command & 4) command &= ~3; /* 4X */ + if (command & 2) + command &= ~5; /* 2X (8X for AGP3.0) */ + if (command & 1) + command &= ~6; /* 1X (4X for AGP3.0) */ + + return command; +} + +static void agp_device_command(u32 command, int agp_v3) +{ + struct pci_dev *device; + int mode; + + mode = command & 0x7; + if (agp_v3) + mode *= 4; + + pci_for_each_dev(device) { + u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; + + printk(KERN_INFO PFX "Putting AGP V%d device at %s into %dx mode\n", + agp_v3 ? 3 : 2, device->slot_name, mode); + pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); } - if (command & 2) { - command &= ~5; /* 2X */ - } - if (command & 1) { - command &= ~6; /* 1X */ - } +} + +static void agp_generic_agp_enable(u32 mode) +{ + u32 command; + + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + PCI_AGP_STATUS, + &command); + + command = agp_collect_device_status(mode, command); command |= 0x00000100; pci_write_config_dword(agp_bridge.dev, - agp_bridge.capndx + 8, + agp_bridge.capndx + PCI_AGP_COMMAND, command); - /* - * PASS3: Go throu all AGP devices and update the - * command registers. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 0); } static int agp_generic_create_gatt_table(void) @@ -1381,9 +1455,605 @@ #endif /* CONFIG_AGP_I810 */ - #ifdef CONFIG_AGP_INTEL +#ifdef CONFIG_AGP_I460 -#endif /* CONFIG_AGP_I810 */ +/* BIOS configures the chipset so that one of two apbase registers are used */ +static u8 intel_i460_dynamic_apbase = 0x10; + +/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ +static u8 intel_i460_pageshift = 12; +static u32 intel_i460_pagesize; + +/* Keep track of which is larger, chipset or kernel page size. */ +static u32 intel_i460_cpk = 1; + +/* Structure for tracking partial use of 4MB GART pages */ +static u32 **i460_pg_detail = NULL; +static u32 *i460_pg_count = NULL; + +#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift) +#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT) + +#define I460_SRAM_IO_DISABLE (1 << 4) +#define I460_BAPBASE_ENABLE (1 << 3) +#define I460_AGPSIZ_MASK 0x7 +#define I460_4M_PS (1 << 1) + +#define log2(x) ffz(~(x)) + +static gatt_mask intel_i460_masks[] = +{ + { INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT, 0 } +}; + +static unsigned long intel_i460_mask_memory(unsigned long addr, int type) +{ + /* Make sure the returned address is a valid GATT entry */ + return (agp_bridge.masks[0].mask | (((addr & + ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12)); +} + +static unsigned long intel_i460_unmask_memory(unsigned long addr) +{ + /* Turn a GATT entry into a physical address */ + return ((addr & 0xffffff) << 12); +} + +static int intel_i460_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + /* Determine the GART page size */ + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp); + intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12; + intel_i460_pagesize = 1UL << intel_i460_pageshift; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + + /* Exit now if the IO drivers for the GART SRAMS are turned off */ + if (temp & I460_SRAM_IO_DISABLE) { + printk(KERN_WARNING PFX "GART SRAMS disabled on 460GX chipset\n"); + printk(KERN_WARNING PFX "AGPGART operation not possible\n"); + return 0; + } + + /* Make sure we don't try to create an 2 ^ 23 entry GATT */ + if ((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) { + printk(KERN_WARNING PFX "We can't have a 32GB aperture with 4KB" + " GART pages\n"); + return 0; + } + + /* Determine the proper APBASE register */ + if (temp & I460_BAPBASE_ENABLE) + intel_i460_dynamic_apbase = INTEL_I460_BAPBASE; + else + intel_i460_dynamic_apbase = INTEL_I460_APBASE; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + + /* + * Dynamically calculate the proper num_entries and page_order + * values for the define aperture sizes. Take care not to + * shift off the end of values[i].size. + */ + values[i].num_entries = (values[i].size << 8) >> + (intel_i460_pageshift - 12); + values[i].page_order = log2((sizeof(u32)*values[i].num_entries) + >> PAGE_SHIFT); + } + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + /* Neglect control bits when matching up size_value */ + if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +/* There isn't anything to do here since 460 has no GART TLB. */ +static void intel_i460_tlb_flush(agp_memory * mem) +{ + return; +} + +/* + * This utility function is needed to prevent corruption of the control bits + * which are stored along with the aperture size in 460's AGPSIZ register + */ +static void intel_i460_write_agpsiz(u8 size_value) +{ + u8 temp; + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, + ((temp & ~I460_AGPSIZ_MASK) | size_value)); +} + +static void intel_i460_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + intel_i460_write_agpsiz(previous_size->size_value); + + if (intel_i460_cpk == 0) { + vfree(i460_pg_detail); + vfree(i460_pg_count); + } +} + + +/* Control bits for Out-Of-GART coherency and Burst Write Combining */ +#define I460_GXBCTL_OOG (1UL << 0) +#define I460_GXBCTL_BWC (1UL << 2) + +static int intel_i460_configure(void) +{ + union { + u32 small[2]; + u64 large; + } temp; + u8 scratch; + int i; + + aper_size_info_8 *current_size; + + temp.large = 0; + + current_size = A_SIZE_8(agp_bridge.current_size); + intel_i460_write_agpsiz(current_size->size_value); + + /* + * Do the necessary rigmarole to read all eight bytes of APBASE. + * This has to be done since the AGP aperture can be above 4GB on + * 460 based systems. + */ + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, + &(temp.small[0])); + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, + &(temp.small[1])); + + /* Clear BAR control bits */ + agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, + (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC); + + /* + * Initialize partial allocation trackers if a GART page is bigger than + * a kernel page. + */ + if (I460_CPAGES_PER_KPAGE >= 1) { + intel_i460_cpk = 1; + } else { + intel_i460_cpk = 0; + + i460_pg_detail = (void *) vmalloc(sizeof(*i460_pg_detail) * + current_size->num_entries); + i460_pg_count = (void *) vmalloc(sizeof(*i460_pg_count) * + current_size->num_entries); + + for (i = 0; i < current_size->num_entries; i++) { + i460_pg_count[i] = 0; + i460_pg_detail[i] = NULL; + } + } + + return 0; +} + +static int intel_i460_create_gatt_table(void) { + + char *table; + int i; + int page_order; + int num_entries; + void *temp; + unsigned int read_back; + + /* + * Load up the fixed address of the GART SRAMS which hold our + * GATT table. + */ + table = (char *) __va(INTEL_I460_ATTBASE); + + temp = agp_bridge.current_size; + page_order = A_SIZE_8(temp)->page_order; + num_entries = A_SIZE_8(temp)->num_entries; + + agp_bridge.gatt_table_real = (u32 *) table; + agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), + (PAGE_SIZE * (1 << page_order))); + agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + return 0; +} + +static int intel_i460_free_gatt_table(void) +{ + int num_entries; + int i; + void *temp; + unsigned int read_back; + + temp = agp_bridge.current_size; + + num_entries = A_SIZE_8(temp)->num_entries; + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + iounmap(agp_bridge.gatt_table); + + return 0; +} + +/* These functions are called when PAGE_SIZE exceeds the GART page size */ + +static int intel_i460_insert_memory_cpk(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, k, num_entries; + void *temp; + unsigned long paddr; + unsigned int read_back; + + /* + * The rest of the kernel will compute page offsets in terms of + * PAGE_SIZE. + */ + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + if ((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) { + printk(KERN_WARNING PFX "Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + j++; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++) { + + paddr = mem->memory[i]; + + for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize) + agp_bridge.gatt_table[j] = (unsigned int) + agp_bridge.mask_memory(paddr, mem->type); + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[j - 1]; + + return 0; +} + +static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned int read_back; + + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * + mem->page_count); i++) + agp_bridge.gatt_table[i] = 0; + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + return 0; +} + +/* + * These functions are called when the GART page size exceeds PAGE_SIZE. + * + * This situation is interesting since AGP memory allocations that are + * smaller than a single GART page are possible. The structures i460_pg_count + * and i460_pg_detail track partial allocation of the large GART pages to + * work around this issue. + * + * i460_pg_count[pg_num] tracks the number of kernel pages in use within + * GART page pg_num. i460_pg_detail[pg_num] is an array containing a + * psuedo-GART entry for each of the aforementioned kernel pages. The whole + * of i460_pg_detail is equivalent to a giant GATT with page size equal to + * that of the kernel. + */ + +static void *intel_i460_alloc_large_page(int pg_num) +{ + int i; + void *bp, *bp_end; + struct page *page; + + i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * + I460_KPAGES_PER_CPAGE); + if (i460_pg_detail[pg_num] == NULL) { + printk(KERN_WARNING PFX "Out of memory, we're in trouble...\n"); + return NULL; + } + + for (i = 0; i < I460_KPAGES_PER_CPAGE; i++) + i460_pg_detail[pg_num][i] = 0; + + bp = (void *) __get_free_pages(GFP_KERNEL, + intel_i460_pageshift - PAGE_SHIFT); + if (bp == NULL) { + printk(KERN_WARNING PFX "Couldn't alloc 4M GART page...\n"); + return NULL; + } + + bp_end = bp + ((PAGE_SIZE * + (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1); + + for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) { + atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); + atomic_inc(&agp_bridge.current_memory_agp); + } + + return bp; +} + +static void intel_i460_free_large_page(int pg_num, unsigned long addr) +{ + struct page *page; + void *bp, *bp_end; + + bp = (void *) __va(addr); + bp_end = bp + (PAGE_SIZE * + (1 << (intel_i460_pageshift - PAGE_SHIFT))); + + vfree(i460_pg_detail[pg_num]); + i460_pg_detail[pg_num] = NULL; + + for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) { + put_page(page); + UnlockPage(page); + atomic_dec(&agp_bridge.current_memory_agp); + } + + free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT); +} + +static int intel_i460_insert_memory_kpc(agp_memory * mem, + off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned int read_back; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / + I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % + I460_KPAGES_PER_CPAGE; + + if (end_pg > num_entries) { + printk(KERN_WARNING PFX "Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + /* Check if the requested region of the aperture is free */ + for (pg = start_pg; pg <= end_pg; pg++) { + /* Allocate new GART pages if necessary */ + if (i460_pg_detail[pg] == NULL) { + temp = intel_i460_alloc_large_page(pg); + if (temp == NULL) + return -ENOMEM; + agp_bridge.gatt_table[pg] = agp_bridge.mask_memory( + (unsigned long) temp, 0); + read_back = agp_bridge.gatt_table[pg]; + } + + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++) { + if(i460_pg_detail[pg][idx] != 0) + return -EBUSY; + } + } + + for (pg = start_pg, i = 0; pg <= end_pg; pg++) { + paddr = intel_i460_unmask_memory(agp_bridge.gatt_table[pg]); + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++, i++) { + mem->memory[i] = paddr + (idx * PAGE_SIZE); + i460_pg_detail[pg][idx] = + agp_bridge.mask_memory(mem->memory[i], mem->type); + + i460_pg_count[pg]++; + } + } + + return 0; +} + +static int intel_i460_remove_memory_kpc(agp_memory * mem, + off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned int read_back; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / + I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % + I460_KPAGES_PER_CPAGE; + + for (i = 0, pg = start_pg; pg <= end_pg; pg++) { + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++, i++) { + mem->memory[i] = 0; + i460_pg_detail[pg][idx] = 0; + i460_pg_count[pg]--; + } + + /* Free GART pages if they are unused */ + if (i460_pg_count[pg] == 0) { + paddr = intel_i460_unmask_memory(agp_bridge.gatt_table[pg]); + agp_bridge.gatt_table[pg] = agp_bridge.scratch_page; + read_back = agp_bridge.gatt_table[pg]; + + intel_i460_free_large_page(pg, paddr); + } + } + + return 0; +} + +/* Dummy routines to call the approriate {cpk,kpc} function */ + +static int intel_i460_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + if (intel_i460_cpk) + return intel_i460_insert_memory_cpk(mem, pg_start, type); + else + return intel_i460_insert_memory_kpc(mem, pg_start, type); +} + +static int intel_i460_remove_memory(agp_memory * mem, + off_t pg_start, int type) +{ + if (intel_i460_cpk) + return intel_i460_remove_memory_cpk(mem, pg_start, type); + else + return intel_i460_remove_memory_kpc(mem, pg_start, type); +} + +/* + * If the kernel page size is smaller that the chipset page size, we don't + * want to allocate memory until we know where it is to be bound in the + * aperture (a multi-kernel-page alloc might fit inside of an already + * allocated GART page). Consequently, don't allocate or free anything + * if i460_cpk (meaning chipset pages per kernel page) isn't set. + * + * Let's just hope nobody counts on the allocated AGP memory being there + * before bind time (I don't think current drivers do)... + */ +static unsigned long intel_i460_alloc_page(void) +{ + if (intel_i460_cpk) + return agp_generic_alloc_page(); + + /* Returning NULL would cause problems */ + return ((unsigned long) ~0UL); +} + +static void intel_i460_destroy_page(unsigned long page) +{ + if (intel_i460_cpk) + agp_generic_destroy_page(page); +} + +static aper_size_info_8 intel_i460_sizes[3] = +{ + /* + * The 32GB aperture is only available with a 4M GART page size. + * Due to the dynamic GART page size, we can't figure out page_order + * or num_entries until runtime. + */ + {32768, 0, 0, 4}, + {1024, 0, 0, 2}, + {256, 0, 0, 1} +}; + +static int __init intel_i460_setup(struct pci_dev *pdev) +{ + agp_bridge.masks = intel_i460_masks; + agp_bridge.aperture_sizes = (void *) intel_i460_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 3; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_i460_configure; + agp_bridge.fetch_size = intel_i460_fetch_size; + agp_bridge.cleanup = intel_i460_cleanup; + agp_bridge.tlb_flush = intel_i460_tlb_flush; + agp_bridge.mask_memory = intel_i460_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = intel_i460_create_gatt_table; + agp_bridge.free_gatt_table = intel_i460_free_gatt_table; + agp_bridge.insert_memory = intel_i460_insert_memory; + agp_bridge.remove_memory = intel_i460_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = intel_i460_alloc_page; + agp_bridge.agp_destroy_page = intel_i460_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 1; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_I460 */ #ifdef CONFIG_AGP_INTEL @@ -3022,7 +3692,6 @@ struct pci_dev *device = NULL; u32 command, scratch; u8 cap_ptr; - u8 agp_v3; u8 v3_devs=0; /* FIXME: If 'mode' is x1/x2/x4 should we call the AGPv2 routines directly ? @@ -3055,77 +3724,14 @@ } - pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command); - - /* - * PASS2: go through all devices that claim to be - * AGP devices and collect their data. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - printk (KERN_INFO "AGP: Setting up AGPv3 capable device at %d:%d:%d\n", - device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn)); - pci_read_config_dword(device, cap_ptr + 4, &scratch); - agp_v3 = (scratch & (1<<3) ) >>3; - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x200) && (scratch & 0x200) && (mode & 0x200))) - command &= ~0x200; - - /* disable FW if it's not supported */ - if (!((command & 0x10) && (scratch & 0x10) && (mode & 0x10))) - command &= ~0x10; - - if (!((command & 2) && (scratch & 2) && (mode & 2))) { - command &= ~2; /* 8x */ - printk (KERN_INFO "AGP: Putting device into 8x mode\n"); - } - - if (!((command & 1) && (scratch & 1) && (mode & 1))) { - command &= ~1; /* 4x */ - printk (KERN_INFO "AGP: Putting device into 4x mode\n"); - } - } - } - /* - * PASS3: Figure out the 8X/4X setting and enable the - * target (our motherboard chipset). - */ - - if (command & 2) - command &= ~5; /* 8X */ - - if (command & 1) - command &= ~6; /* 4X */ + pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + PCI_AGP_STATUS, &command); + command = agp_collect_device_status(mode, command); command |= 0x100; - pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + 8, command); - - /* - * PASS4: Go through all AGP devices and update the - * command registers. - */ + pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + PCI_AGP_COMMAND, command); - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 1); } @@ -3682,7 +4288,7 @@ /* Fill in the mode register */ pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); pci_read_config_byte(agp_bridge.dev, @@ -3832,104 +4438,23 @@ static void serverworks_agp_enable(u32 mode) { - struct pci_dev *device = NULL; - u32 command, scratch, cap_id; - u8 cap_ptr; + u32 command; pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &command); - /* - * PASS1: go throu all devices that claim to be - * AGP devices and collect their data. - */ - - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - pci_read_config_dword(device, cap_ptr + 4, &scratch); - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; - - /* disable FW */ - command &= ~0x00000010; + command = agp_collect_device_status(mode, command); - command &= ~0x00000008; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; - } - } - /* - * PASS2: Figure out the 4X/2X/1X setting and enable the - * target (our motherboard chipset). - */ - - if (command & 4) { - command &= ~3; /* 4X */ - } - if (command & 2) { - command &= ~5; /* 2X */ - } - if (command & 1) { - command &= ~6; /* 1X */ - } + command &= ~0x00000010; /* disable FW */ + command &= ~0x00000008; command |= 0x00000100; pci_write_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 8, + agp_bridge.capndx + PCI_AGP_COMMAND, command); - /* - * PASS3: Go throu all AGP devices and update the - * command registers. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 0); } static int __init serverworks_setup (struct pci_dev *pdev) @@ -4009,6 +4534,8 @@ #define log2(x) ffz(~(x)) #endif +#define HP_ZX1_IOC_OFFSET 0x1000 /* ACPI reports SBA, we want IOC */ + #define HP_ZX1_IOVA_BASE GB(1UL) #define HP_ZX1_IOVA_SIZE GB(1UL) #define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2) @@ -4023,14 +4550,9 @@ {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */ }; -static gatt_mask hp_zx1_masks[] = -{ - {HP_ZX1_PDIR_VALID_BIT, 0} -}; - static struct _hp_private { - struct pci_dev *ioc; - volatile u8 *registers; + volatile u8 *ioc_regs; + volatile u8 *lba_regs; u64 *io_pdir; // PDIR for entire IOVA u64 *gatt; // PDIR just for GART (subset of above) u64 gatt_entries; @@ -4057,7 +4579,7 @@ * - IOVA space is 1Gb in size * - first 512Mb is IOMMU, second 512Mb is GART */ - hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG); + hp->io_tlb_ps = INREG64(hp->ioc_regs, HP_ZX1_TCNFG); switch (hp->io_tlb_ps) { case 0: hp->io_tlb_shift = 12; break; case 1: hp->io_tlb_shift = 13; break; @@ -4073,13 +4595,13 @@ hp->io_page_size = 1 << hp->io_tlb_shift; hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; - hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1; + hp->iova_base = INREG64(hp->ioc_regs, HP_ZX1_IBASE) & ~0x1; hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE; hp->gart_size = HP_ZX1_GART_SIZE; hp->gatt_entries = hp->gart_size / hp->io_page_size; - hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE)); + hp->io_pdir = phys_to_virt(INREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE)); hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { @@ -4093,7 +4615,7 @@ return 0; } -static int __init hp_zx1_ioc_owner(u8 ioc_rev) +static int __init hp_zx1_ioc_owner(void) { struct _hp_private *hp = &hp_private; @@ -4128,44 +4650,21 @@ return 0; } -static int __init hp_zx1_ioc_init(void) +static int __init hp_zx1_ioc_init(u64 ioc_hpa, u64 lba_hpa) { struct _hp_private *hp = &hp_private; - struct pci_dev *ioc; - int i; - u8 ioc_rev; - ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL); - if (!ioc) { - printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n"); - return -ENODEV; - } - hp->ioc = ioc; - - pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev); - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) { - hp->registers = (u8 *) ioremap(pci_resource_start(ioc, - i), - pci_resource_len(ioc, i)); - break; - } - } - if (!hp->registers) { - printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n"); - - return -ENODEV; - } + hp->ioc_regs = ioremap(ioc_hpa, 1024); + hp->lba_regs = ioremap(lba_hpa, 256); /* * If the IOTLB is currently disabled, we can take it over. * Otherwise, we have to share with sba_iommu. */ - hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0; + hp->io_pdir_owner = (INREG64(hp->ioc_regs, HP_ZX1_IBASE) & 0x1) == 0; if (hp->io_pdir_owner) - return hp_zx1_ioc_owner(ioc_rev); + return hp_zx1_ioc_owner(); return hp_zx1_ioc_shared(); } @@ -4185,19 +4684,17 @@ struct _hp_private *hp = &hp_private; agp_bridge.gart_bus_addr = hp->gart_base; - agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP); - pci_read_config_dword(agp_bridge.dev, - agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); + agp_bridge.mode = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS); if (hp->io_pdir_owner) { - OUTREG64(hp->registers, HP_ZX1_PDIR_BASE, + OUTREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE, virt_to_phys(hp->io_pdir)); - OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps); - OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1)); - OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1); - OUTREG64(hp->registers, HP_ZX1_PCOM, + OUTREG64(hp->ioc_regs, HP_ZX1_TCNFG, hp->io_tlb_ps); + OUTREG64(hp->ioc_regs, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1)); + OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, hp->iova_base | 0x1); + OUTREG64(hp->ioc_regs, HP_ZX1_PCOM, hp->iova_base | log2(HP_ZX1_IOVA_SIZE)); - INREG64(hp->registers, HP_ZX1_PCOM); + INREG64(hp->ioc_regs, HP_ZX1_PCOM); } return 0; @@ -4208,17 +4705,18 @@ struct _hp_private *hp = &hp_private; if (hp->io_pdir_owner) - OUTREG64(hp->registers, HP_ZX1_IBASE, 0); - iounmap((void *) hp->registers); + OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); + iounmap((void *) hp->ioc_regs); + iounmap((void *) hp->lba_regs); } static void hp_zx1_tlbflush(agp_memory * mem) { struct _hp_private *hp = &hp_private; - OUTREG64(hp->registers, HP_ZX1_PCOM, + OUTREG64(hp->ioc_regs, HP_ZX1_PCOM, hp->gart_base | log2(hp->gart_size)); - INREG64(hp->registers, HP_ZX1_PCOM); + INREG64(hp->ioc_regs, HP_ZX1_PCOM); } static int hp_zx1_create_gatt_table(void) @@ -4285,11 +4783,6 @@ j++; } - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } - for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; @@ -4329,14 +4822,23 @@ return HP_ZX1_PDIR_VALID_BIT | addr; } -static unsigned long hp_zx1_unmask_memory(unsigned long addr) +static void hp_zx1_agp_enable(u32 mode) { - return addr & ~(HP_ZX1_PDIR_VALID_BIT); + struct _hp_private *hp = &hp_private; + u32 command; + + command = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS); + + command = agp_collect_device_status(mode, command); + command |= 0x00000100; + + OUTREG32(hp->lba_regs, HP_ZX1_AGP_COMMAND, command); + + agp_device_command(command, 0); } -static int __init hp_zx1_setup (struct pci_dev *pdev) +static int __init hp_zx1_setup(u64 ioc_hpa, u64 lba_hpa) { - agp_bridge.masks = hp_zx1_masks; agp_bridge.dev_private_data = NULL; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.needs_scratch_page = FALSE; @@ -4345,8 +4847,7 @@ agp_bridge.cleanup = hp_zx1_cleanup; agp_bridge.tlb_flush = hp_zx1_tlbflush; agp_bridge.mask_memory = hp_zx1_mask_memory; - agp_bridge.unmask_memory = hp_zx1_unmask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.agp_enable = hp_zx1_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = hp_zx1_create_gatt_table; agp_bridge.free_gatt_table = hp_zx1_free_gatt_table; @@ -4357,12 +4858,61 @@ agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; agp_bridge.cant_use_aperture = 1; + agp_bridge.type = HP_ZX1; - return hp_zx1_ioc_init(); + fake_bridge_dev.vendor = PCI_VENDOR_ID_HP; + fake_bridge_dev.device = PCI_DEVICE_ID_HP_ZX1_LBA; - (void) pdev; /* unused */ + return hp_zx1_ioc_init(ioc_hpa, lba_hpa); +} + +static int __init acpi_hp_zx1_gart_add(struct acpi_device *device) +{ + acpi_handle handle, parent; + acpi_status status; + acpi_device_info info; + u64 lba_hpa, sba_hpa, length; + + status = acpi_hp_csr_space(device->handle, &lba_hpa, &length); + if (ACPI_FAILURE(status)) + return 1; + + /* Look for an enclosing IOC scope and find its CSR space */ + handle = device->handle; + do { + status = acpi_get_object_info(handle, &info); + if (ACPI_SUCCESS(status)) { + /* TBD check _CID also */ + info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; + if (!strcmp(info.hardware_id, "HWP0001")) { + status = acpi_hp_csr_space(handle, &sba_hpa, + &length); + if (ACPI_SUCCESS(status)) + break; + else { + printk(KERN_ERR PFX "Detected HP ZX1 " + "AGP LBA but no IOC.\n"); + return 1; + } + } + } + + status = acpi_get_parent(handle, &parent); + handle = parent; + } while (ACPI_SUCCESS(status)); + + if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa)) + return 1; + + return 0; } +static struct acpi_driver acpi_hp_zx1_gart_driver = { + .name = "HP ZX1 GART Driver", + .ids = "HWP0003", + .ops = { .add = acpi_hp_zx1_gart_add }, +}; + #endif /* CONFIG_AGP_HP_ZX1 */ /* per-chipset initialization data. @@ -4558,6 +5108,15 @@ #endif /* CONFIG_AGP_INTEL */ +#ifdef CONFIG_AGP_I460 + { PCI_DEVICE_ID_INTEL_460GX, + PCI_VENDOR_ID_INTEL, + INTEL_460GX, + "Intel", + "460GX", + intel_i460_setup }, +#endif + #ifdef CONFIG_AGP_SIS { PCI_DEVICE_ID_SI_740, PCI_VENDOR_ID_SI, @@ -4696,15 +5255,6 @@ via_generic_setup }, #endif /* CONFIG_AGP_VIA */ -#ifdef CONFIG_AGP_HP_ZX1 - { PCI_DEVICE_ID_HP_ZX1_LBA, - PCI_VENDOR_ID_HP, - HP_ZX1, - "HP", - "ZX1", - hp_zx1_setup }, -#endif - { 0, }, /* dummy final entry, always present */ }; @@ -4783,6 +5333,18 @@ return -ENODEV; } +static int agp_check_supported_device(struct pci_dev *dev) { + + int i; + + for (i = 0; i < ARRAY_SIZE (agp_bridge_info); i++) { + if (dev->vendor == agp_bridge_info[i].vendor_id && + dev->device == agp_bridge_info[i].device_id) + return 1; + } + + return 0; +} /* Supported Device Scanning routine */ @@ -4791,8 +5353,24 @@ struct pci_dev *dev = NULL; u8 cap_ptr = 0x00; - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) - return -ENODEV; +#ifdef CONFIG_AGP_HP_ZX1 + int rc; + + rc = acpi_bus_register_driver(&acpi_hp_zx1_gart_driver); + if (rc > 0) { + printk(KERN_INFO PFX "Detected an HP ZX1 Chipset.\n"); + return 0; + } +#endif + + /* + * Some systems have multiple host bridges, so + * we can't just use the first one we find. + */ + do { + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev)) == NULL) + return -ENODEV; + } while (!agp_check_supported_device(dev)); agp_bridge.dev = dev; @@ -4952,23 +5530,6 @@ #endif /* CONFIG_AGP_SWORKS */ -#ifdef CONFIG_AGP_HP_ZX1 - if (dev->vendor == PCI_VENDOR_ID_HP) { - do { - /* ZX1 LBAs can be either PCI or AGP bridges */ - if (pci_find_capability(dev, PCI_CAP_ID_AGP)) { - printk(KERN_INFO PFX "Detected HP ZX1 AGP " - "chipset at %s\n", dev->slot_name); - agp_bridge.type = HP_ZX1; - agp_bridge.dev = dev; - return hp_zx1_setup(dev); - } - dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev); - } while (dev); - return -ENODEV; - } -#endif /* CONFIG_AGP_HP_ZX1 */ - /* find capndx */ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); if (cap_ptr == 0x00) @@ -4977,7 +5538,7 @@ /* Fill in the mode register */ pci_read_config_dword(agp_bridge.dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); /* probe for known chipsets */ @@ -5175,7 +5736,8 @@ inter_module_register("drm_agp", THIS_MODULE, &drm_agp); - pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power); + if (agp_bridge.dev) + pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power); return 0; } diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Wed Oct 8 09:08:18 2003 +++ b/drivers/pci/pci.c Wed Oct 8 09:08:18 2003 @@ -1058,8 +1058,14 @@ { unsigned int pos, reg, next; u32 l, sz; + u16 cmd; struct resource *res; + /* Disable I/O & memory decoding while we size the BARs. */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for(pos=0; posresource[pos]; @@ -1131,6 +1137,8 @@ res->end = res->start + (unsigned long) sz; } } + + pci_write_config_word(dev, PCI_COMMAND, cmd); } void __devinit pci_read_bridge_bases(struct pci_bus *child) @@ -2050,16 +2058,16 @@ int map, block; if ((page = pool_find_page (pool, dma)) == 0) { - printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n", + printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, (unsigned long) dma); return; } #ifdef CONFIG_PCIPOOL_DEBUG if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n", + printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, (unsigned long) dma); return; } #endif diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h --- a/include/asm-i386/fixmap.h Wed Oct 8 09:08:18 2003 +++ b/include/asm-i386/fixmap.h Wed Oct 8 09:08:18 2003 @@ -15,6 +15,7 @@ #include #include +#include #include #include #ifdef CONFIG_HIGHMEM @@ -57,7 +58,7 @@ #endif #ifdef CONFIG_X86_VISWS_APIC FIX_CO_CPU, /* Cobalt timer */ - FIX_CO_APIC, /* Cobalt APIC Redirection Table */ + FIX_CO_APIC, /* Cobalt APIC Redirection Table */ FIX_LI_PCIA, /* Lithium PCI Bridge A */ FIX_LI_PCIB, /* Lithium PCI Bridge B */ #endif @@ -70,6 +71,10 @@ #ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, +#endif +#ifdef CONFIG_ACPI_BOOT + FIX_ACPI_BEGIN, + FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, #endif __end_of_permanent_fixed_addresses, /* temporary boot-time mappings, used before ioremap() is functional */